package org.colafries.admin.querybuilder.customQuery;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Strings;
import org.colafries.admin.entity.domain.DataModelConfig;
import org.colafries.admin.entity.vo.CustomQueryReqVO;
import org.colafries.admin.exceptions.ServiceException;
import org.colafries.admin.querybuilder.entity.CustomQueryParamContext;
import org.colafries.admin.querybuilder.entity.CustomQuerySqlBuildContext;
import org.colafries.admin.querybuilder.utils.SqlSegmentBuilderUtil;
import org.colafries.common.constants.OperatorConstant;
import org.colafries.common.enums.ColumnDataTypeEnum;
import org.colafries.common.enums.Flag;
import org.colafries.admin.entity.domain.QueryParam;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author colafries
 * @version v1.0
 * @ClassName ConditionPartBuilder
 * @Description
 * @date Created in 2024/5/15
 **/
public class CustomQueryConditionBuilder implements CustomQuerySqlSegmentBuilder {
    /**
     * @param customQueryParam
     * @return void
     * @author colafries
     * @Date 2024/5/16
     */
    @Override
    public void buildQueryParma(CustomQueryReqVO.CustomQueryParam customQueryParam, CustomQueryParamContext customQueryParamContext) {

        // Condition
        Optional.ofNullable(customQueryParam)
                .map(CustomQueryReqVO.CustomQueryParam::getConditions)
                .ifPresent(conditions -> {
                    conditions.forEach(condition -> {
                        DataModelConfig dataModelConfig = customQueryParamContext.getDataModelConfigMap().get(condition.getFieldHash());
                        customQueryParamContext.getConditions().add(
                                Optional.ofNullable(dataModelConfig)
                                        .map(config -> QueryParam.Condition.builder()
                                                .field(dataModelConfig.getField())
                                                .fieldHash(condition.getFieldHash())
                                                .dataType(dataModelConfig.getDataType())
                                                .operator(condition.getOperator())
                                                .fieldValue(condition.getValue())
                                                .expression(dataModelConfig.getExpression())
                                                .calculatedFlag(dataModelConfig.getCalculatedFlag())
                                                .build()
                                        ).orElseThrow(() -> new ServiceException("维度不存在 fieldHash：" + condition.getFieldHash()))
                        );
                    });
                });
    }

    /**
     * conditionPart:whereConditions
     *
     * @param queryParam
     * @param customQuerySqlQueryContext
     * @return void
     * @author colafries
     * @Date 2024/5/16
     */
    @Override
    public void buildQuery(QueryParam queryParam, CustomQuerySqlBuildContext customQuerySqlQueryContext) {
        // conditions
        List<QueryParam.Condition> conditions = Optional.of(queryParam).map(QueryParam::getConditions)
                .orElse(Collections.emptyList());
        // condition
        conditions.forEach(condition -> {
            // 根据dimension.fieldHash 获取自定义表Column
            Optional.ofNullable(customQuerySqlQueryContext.getCustomTableSchemaMap().get(condition.getFieldHash()))
                    .ifPresent(customTableColumn -> {
                        String tableHash = customTableColumn.getTableHash();
                        String fieldHash = customTableColumn.getFieldHash();
                        if (fieldHash.equals(condition.getFieldHash())) {
                            condition.setTableHash(tableHash);
                        }
                    });
        });

        // where（conditionList）
        if (!CollectionUtil.isEmpty(conditions)) {
            conditions.forEach(condition -> {
                customQuerySqlQueryContext.getWhereConditions().add(buildConditionExpression(condition, customQuerySqlQueryContext.getFildExpMap()));
            });
        }
    }
    /**
     * 构建where条件表达式
         * 如果 calculatedFlag = YES, expression = covert(expression)
         * 如果 calculatedFlag = NO, expression = `tableHash`.`field`
         * 条件表达式：
         * 类型:DATE
         *          value = starDateTime,endDateTime
         *          startDateTime = split(value,',').get(0)
         *          endDateTime = split(value,',').get(1)
         *          expression :expression >= startDateTime AND tableHash.field <= endDateTime
         * 类型:STRING    expression like '%value%'
         * 类型:INT       expression = value
         * 类型:DOUBLE    expression = value
     * @param condition Query Condition
     * @param fieldExpMap map
     * @return java.lang.String
     * @author colafries
     * @Date 2024/5/16
     */
    private String buildConditionExpression(QueryParam.Condition condition, Map<String, String> fieldExpMap){
        String field = condition.getField();
        ColumnDataTypeEnum dataType = condition.getDataType();
        String operator = condition.getOperator();
        String value = condition.getFieldValue();
        // 构建表达式
        String expression = condition.getExpression();
        if (Flag.YES == condition.getCalculatedFlag()) {
            // 替换表达式中的{fieldHash}

            expression = SqlSegmentBuilderUtil.convertExpression(expression, fieldExpMap);
        } else {
            expression = String.format("`%s`.`%s`", condition.getTableHash(), field);
        }
        // 构建条件表达式
        if (ColumnDataTypeEnum.DATE == dataType) {
            if (!Strings.isNullOrEmpty(value)) {
                String[] dateTimeArray = StrUtil.split(value, ",");
                // 获取开始时间、结束时间
                String startDateTime = dateTimeArray.length > 0 ? dateTimeArray[0] : "";
                String endDateTime = dateTimeArray.length > 1 ? dateTimeArray[1] : "";
                return String.format("%s >= '%s' AND %s <= '%s'", expression, startDateTime, expression, endDateTime);
            }
            return "";
        } else if (ColumnDataTypeEnum.STRING == dataType) {
            operator = Optional.ofNullable(operator).orElse(OperatorConstant.LIKE);
            // 如果操作符==IN
            if (OperatorConstant.IN.equals(operator)){
                // value 转换成 SQL IN (xxxx) 支持的格式
                value = convertToQuotedString(value);
                return String.format("%s %s (%s)", expression, operator, value);
            }
            // value 值例如 C01,C02 .. .. --> expression LIKE '%C01%' OR expression LIKE '%C02%' ... ...
            return buildLikeConditionExpression(expression, operator, value);
        } else if (ColumnDataTypeEnum.INT == dataType) {
            operator = Optional.ofNullable(operator).orElse(OperatorConstant.EQ);
            // 如果操作符==IN
            if (OperatorConstant.IN.equals(operator)){
                return String.format("%s %s (%s)", expression, operator, value);
            }
            return String.format("%s %s %s", expression, operator, value);
        } else if (ColumnDataTypeEnum.DOUBLE == dataType) {
            operator = Optional.ofNullable(operator).orElse(OperatorConstant.EQ);
            // 如果操作符==IN
            if (OperatorConstant.IN.equals(operator)){
                return String.format("%s %s (%s)", expression, operator, value);
            }
            return String.format("%s %s %s", expression, operator, value);
        }
        return null;
    }

    /**
     * 构建LIKE条件表达式
     *  expression LIKE '%C01%' OR expression LIKE '%C02%' ... ...
     * @param expression
     * @param operator
     * @param value
     * @return
     */
    public String buildLikeConditionExpression(String expression, String operator, String value) {
        List<String> valueList = Arrays.asList(value.split(","));
        String conditionExpression = valueList.stream()
                .map(s -> String.format("%s %s '%%%s%%'", expression, operator, s.trim()))
                .collect(Collectors.joining(" OR "));
        return String.format("(%s)", conditionExpression);
    }

    /**
     * 字符串转换 a,b,c 转换成 'a','b','c'
     * @param value
     * @return java.lang.String
     * @author colafries
     * @Date 2024/5/22
     */
    public String convertToQuotedString(String value){
        List<String> valueList = Arrays.asList(value.split(","));
        //convert to 'a','b','c', .. ...
        return valueList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));

    }
}
